/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
use winit::event::{ElementState, KeyEvent};
use winit::keyboard::{
    Key as WinitKey, KeyCode, KeyLocation as WinitKeyLocation, ModifiersState, NamedKey,
    PhysicalKey,
};

// Some shortcuts use Cmd on Mac and Control on other systems.
#[cfg(target_os = "macos")]
pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
#[cfg(not(target_os = "macos"))]
pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;

// Some shortcuts use Cmd on Mac and Alt on other systems.
#[cfg(target_os = "macos")]
pub const CMD_OR_ALT: Modifiers = Modifiers::META;
#[cfg(not(target_os = "macos"))]
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;

trait FromWinitKeyEvent {
    fn from_winit_key_event(key_event: &KeyEvent) -> Self;
}

impl FromWinitKeyEvent for Key {
    fn from_winit_key_event(key_event: &KeyEvent) -> Self {
        let named_key = match key_event.logical_key {
            WinitKey::Named(named_key) => named_key,
            WinitKey::Character(ref string) => return Key::Character(string.to_string()),
            WinitKey::Unidentified(_) => return Key::Unidentified,
            WinitKey::Dead(_) => return Key::Unidentified,
        };

        match named_key {
            NamedKey::AVRInput => Key::AVRInput,
            NamedKey::AVRPower => Key::AVRPower,
            NamedKey::Accept => Key::Accept,
            NamedKey::Again => Key::Again,
            NamedKey::AllCandidates => Key::AllCandidates,
            NamedKey::Alphanumeric => Key::Alphanumeric,
            NamedKey::Alt => Key::Alt,
            NamedKey::AltGraph => Key::AltGraph,
            NamedKey::AppSwitch => Key::AppSwitch,
            NamedKey::ArrowDown => Key::ArrowDown,
            NamedKey::ArrowLeft => Key::ArrowLeft,
            NamedKey::ArrowRight => Key::ArrowRight,
            NamedKey::ArrowUp => Key::ArrowUp,
            NamedKey::Attn => Key::Attn,
            NamedKey::AudioBalanceLeft => Key::AudioBalanceLeft,
            NamedKey::AudioBalanceRight => Key::AudioBalanceRight,
            NamedKey::AudioBassBoostDown => Key::AudioBassBoostDown,
            NamedKey::AudioBassBoostToggle => Key::AudioBassBoostToggle,
            NamedKey::AudioBassBoostUp => Key::AudioBassBoostUp,
            NamedKey::AudioFaderFront => Key::AudioFaderFront,
            NamedKey::AudioFaderRear => Key::AudioFaderRear,
            NamedKey::AudioSurroundModeNext => Key::AudioSurroundModeNext,
            NamedKey::AudioTrebleDown => Key::AudioTrebleDown,
            NamedKey::AudioTrebleUp => Key::AudioTrebleUp,
            NamedKey::AudioVolumeDown => Key::AudioVolumeDown,
            NamedKey::AudioVolumeMute => Key::AudioVolumeMute,
            NamedKey::AudioVolumeUp => Key::AudioVolumeUp,
            NamedKey::Backspace => Key::Backspace,
            NamedKey::BrightnessDown => Key::BrightnessDown,
            NamedKey::BrightnessUp => Key::BrightnessUp,
            NamedKey::BrowserBack => Key::BrowserBack,
            NamedKey::BrowserFavorites => Key::BrowserFavorites,
            NamedKey::BrowserForward => Key::BrowserForward,
            NamedKey::BrowserHome => Key::BrowserHome,
            NamedKey::BrowserRefresh => Key::BrowserRefresh,
            NamedKey::BrowserSearch => Key::BrowserSearch,
            NamedKey::BrowserStop => Key::BrowserStop,
            NamedKey::Call => Key::Call,
            NamedKey::Camera => Key::Camera,
            NamedKey::CameraFocus => Key::CameraFocus,
            NamedKey::Cancel => Key::Cancel,
            NamedKey::CapsLock => Key::CapsLock,
            NamedKey::ChannelDown => Key::ChannelDown,
            NamedKey::ChannelUp => Key::ChannelUp,
            NamedKey::Clear => Key::Clear,
            NamedKey::Close => Key::Close,
            NamedKey::ClosedCaptionToggle => Key::ClosedCaptionToggle,
            NamedKey::CodeInput => Key::CodeInput,
            NamedKey::ColorF0Red => Key::ColorF0Red,
            NamedKey::ColorF1Green => Key::ColorF1Green,
            NamedKey::ColorF2Yellow => Key::ColorF2Yellow,
            NamedKey::ColorF3Blue => Key::ColorF3Blue,
            NamedKey::ColorF4Grey => Key::ColorF4Grey,
            NamedKey::ColorF5Brown => Key::ColorF5Brown,
            NamedKey::Compose => Key::Compose,
            NamedKey::ContextMenu => Key::ContextMenu,
            NamedKey::Control => Key::Control,
            NamedKey::Convert => Key::Convert,
            NamedKey::Copy => Key::Copy,
            NamedKey::CrSel => Key::CrSel,
            NamedKey::Cut => Key::Cut,
            NamedKey::DVR => Key::DVR,
            NamedKey::Delete => Key::Delete,
            NamedKey::Dimmer => Key::Dimmer,
            NamedKey::DisplaySwap => Key::DisplaySwap,
            NamedKey::Eisu => Key::Eisu,
            NamedKey::Eject => Key::Eject,
            NamedKey::End => Key::End,
            NamedKey::EndCall => Key::EndCall,
            NamedKey::Enter => Key::Enter,
            NamedKey::EraseEof => Key::EraseEof,
            NamedKey::Escape => Key::Escape,
            NamedKey::ExSel => Key::ExSel,
            NamedKey::Execute => Key::Execute,
            NamedKey::Exit => Key::Exit,
            NamedKey::F1 => Key::F1,
            NamedKey::F10 => Key::F10,
            NamedKey::F11 => Key::F11,
            NamedKey::F12 => Key::F12,
            NamedKey::F13 => Key::F13,
            NamedKey::F14 => Key::F14,
            NamedKey::F15 => Key::F15,
            NamedKey::F16 => Key::F16,
            NamedKey::F17 => Key::F17,
            NamedKey::F18 => Key::F18,
            NamedKey::F19 => Key::F19,
            NamedKey::F2 => Key::F2,
            NamedKey::F20 => Key::F20,
            NamedKey::F21 => Key::F21,
            NamedKey::F22 => Key::F22,
            NamedKey::F23 => Key::F23,
            NamedKey::F24 => Key::F24,
            NamedKey::F25 => Key::F25,
            NamedKey::F26 => Key::F26,
            NamedKey::F27 => Key::F27,
            NamedKey::F28 => Key::F28,
            NamedKey::F29 => Key::F29,
            NamedKey::F3 => Key::F3,
            NamedKey::F30 => Key::F30,
            NamedKey::F31 => Key::F31,
            NamedKey::F32 => Key::F32,
            NamedKey::F33 => Key::F33,
            NamedKey::F34 => Key::F34,
            NamedKey::F35 => Key::F35,
            NamedKey::F4 => Key::F4,
            NamedKey::F5 => Key::F5,
            NamedKey::F6 => Key::F6,
            NamedKey::F7 => Key::F7,
            NamedKey::F8 => Key::F8,
            NamedKey::F9 => Key::F9,
            NamedKey::FavoriteClear0 => Key::FavoriteClear0,
            NamedKey::FavoriteClear1 => Key::FavoriteClear1,
            NamedKey::FavoriteClear2 => Key::FavoriteClear2,
            NamedKey::FavoriteClear3 => Key::FavoriteClear3,
            NamedKey::FavoriteRecall0 => Key::FavoriteRecall0,
            NamedKey::FavoriteRecall1 => Key::FavoriteRecall1,
            NamedKey::FavoriteRecall2 => Key::FavoriteRecall2,
            NamedKey::FavoriteRecall3 => Key::FavoriteRecall3,
            NamedKey::FavoriteStore0 => Key::FavoriteStore0,
            NamedKey::FavoriteStore1 => Key::FavoriteStore1,
            NamedKey::FavoriteStore2 => Key::FavoriteStore2,
            NamedKey::FavoriteStore3 => Key::FavoriteStore3,
            NamedKey::FinalMode => Key::FinalMode,
            NamedKey::Find => Key::Find,
            NamedKey::Fn => Key::Fn,
            NamedKey::FnLock => Key::FnLock,
            NamedKey::GoBack => Key::GoBack,
            NamedKey::GoHome => Key::GoHome,
            NamedKey::GroupFirst => Key::GroupFirst,
            NamedKey::GroupLast => Key::GroupLast,
            NamedKey::GroupNext => Key::GroupNext,
            NamedKey::GroupPrevious => Key::GroupPrevious,
            NamedKey::Guide => Key::Guide,
            NamedKey::GuideNextDay => Key::GuideNextDay,
            NamedKey::GuidePreviousDay => Key::GuidePreviousDay,
            NamedKey::HangulMode => Key::HangulMode,
            NamedKey::HanjaMode => Key::HanjaMode,
            NamedKey::Hankaku => Key::Hankaku,
            NamedKey::HeadsetHook => Key::HeadsetHook,
            NamedKey::Help => Key::Help,
            NamedKey::Hibernate => Key::Hibernate,
            NamedKey::Hiragana => Key::Hiragana,
            NamedKey::HiraganaKatakana => Key::HiraganaKatakana,
            NamedKey::Home => Key::Home,
            NamedKey::Hyper => Key::Hyper,
            NamedKey::Info => Key::Info,
            NamedKey::Insert => Key::Insert,
            NamedKey::InstantReplay => Key::InstantReplay,
            NamedKey::JunjaMode => Key::JunjaMode,
            NamedKey::KanaMode => Key::KanaMode,
            NamedKey::KanjiMode => Key::KanjiMode,
            NamedKey::Katakana => Key::Katakana,
            NamedKey::Key11 => Key::Key11,
            NamedKey::Key12 => Key::Key12,
            NamedKey::LastNumberRedial => Key::LastNumberRedial,
            NamedKey::LaunchApplication1 => Key::LaunchApplication1,
            NamedKey::LaunchApplication2 => Key::LaunchApplication2,
            NamedKey::LaunchCalendar => Key::LaunchCalendar,
            NamedKey::LaunchContacts => Key::LaunchContacts,
            NamedKey::LaunchMail => Key::LaunchMail,
            NamedKey::LaunchMediaPlayer => Key::LaunchMediaPlayer,
            NamedKey::LaunchMusicPlayer => Key::LaunchMusicPlayer,
            NamedKey::LaunchPhone => Key::LaunchPhone,
            NamedKey::LaunchScreenSaver => Key::LaunchScreenSaver,
            NamedKey::LaunchSpreadsheet => Key::LaunchSpreadsheet,
            NamedKey::LaunchWebBrowser => Key::LaunchWebBrowser,
            NamedKey::LaunchWebCam => Key::LaunchWebCam,
            NamedKey::LaunchWordProcessor => Key::LaunchWordProcessor,
            NamedKey::Link => Key::Link,
            NamedKey::ListProgram => Key::ListProgram,
            NamedKey::LiveContent => Key::LiveContent,
            NamedKey::Lock => Key::Lock,
            NamedKey::LogOff => Key::LogOff,
            NamedKey::MailForward => Key::MailForward,
            NamedKey::MailReply => Key::MailReply,
            NamedKey::MailSend => Key::MailSend,
            NamedKey::MannerMode => Key::MannerMode,
            NamedKey::MediaApps => Key::MediaApps,
            NamedKey::MediaAudioTrack => Key::MediaAudioTrack,
            NamedKey::MediaClose => Key::MediaClose,
            NamedKey::MediaFastForward => Key::MediaFastForward,
            NamedKey::MediaLast => Key::MediaLast,
            NamedKey::MediaPause => Key::MediaPause,
            NamedKey::MediaPlay => Key::MediaPlay,
            NamedKey::MediaPlayPause => Key::MediaPlayPause,
            NamedKey::MediaRecord => Key::MediaRecord,
            NamedKey::MediaRewind => Key::MediaRewind,
            NamedKey::MediaSkipBackward => Key::MediaSkipBackward,
            NamedKey::MediaSkipForward => Key::MediaSkipForward,
            NamedKey::MediaStepBackward => Key::MediaStepBackward,
            NamedKey::MediaStepForward => Key::MediaStepForward,
            NamedKey::MediaStop => Key::MediaStop,
            NamedKey::MediaTopMenu => Key::MediaTopMenu,
            NamedKey::MediaTrackNext => Key::MediaTrackNext,
            NamedKey::MediaTrackPrevious => Key::MediaTrackPrevious,
            NamedKey::Meta => Key::Meta,
            NamedKey::MicrophoneToggle => Key::MicrophoneToggle,
            NamedKey::MicrophoneVolumeDown => Key::MicrophoneVolumeDown,
            NamedKey::MicrophoneVolumeMute => Key::MicrophoneVolumeMute,
            NamedKey::MicrophoneVolumeUp => Key::MicrophoneVolumeUp,
            NamedKey::ModeChange => Key::ModeChange,
            NamedKey::NavigateIn => Key::NavigateIn,
            NamedKey::NavigateNext => Key::NavigateNext,
            NamedKey::NavigateOut => Key::NavigateOut,
            NamedKey::NavigatePrevious => Key::NavigatePrevious,
            NamedKey::New => Key::New,
            NamedKey::NextCandidate => Key::NextCandidate,
            NamedKey::NextFavoriteChannel => Key::NextFavoriteChannel,
            NamedKey::NextUserProfile => Key::NextUserProfile,
            NamedKey::NonConvert => Key::NonConvert,
            NamedKey::Notification => Key::Notification,
            NamedKey::NumLock => Key::NumLock,
            NamedKey::OnDemand => Key::OnDemand,
            NamedKey::Open => Key::Open,
            NamedKey::PageDown => Key::PageDown,
            NamedKey::PageUp => Key::PageUp,
            NamedKey::Pairing => Key::Pairing,
            NamedKey::Paste => Key::Paste,
            NamedKey::Pause => Key::Pause,
            NamedKey::PinPDown => Key::PinPDown,
            NamedKey::PinPMove => Key::PinPMove,
            NamedKey::PinPToggle => Key::PinPToggle,
            NamedKey::PinPUp => Key::PinPUp,
            NamedKey::Play => Key::Play,
            NamedKey::PlaySpeedDown => Key::PlaySpeedDown,
            NamedKey::PlaySpeedReset => Key::PlaySpeedReset,
            NamedKey::PlaySpeedUp => Key::PlaySpeedUp,
            NamedKey::Power => Key::Power,
            NamedKey::PowerOff => Key::PowerOff,
            NamedKey::PreviousCandidate => Key::PreviousCandidate,
            NamedKey::Print => Key::Print,
            NamedKey::PrintScreen => Key::PrintScreen,
            NamedKey::Process => Key::Process,
            NamedKey::Props => Key::Props,
            NamedKey::RandomToggle => Key::RandomToggle,
            NamedKey::RcLowBattery => Key::RcLowBattery,
            NamedKey::RecordSpeedNext => Key::RecordSpeedNext,
            NamedKey::Redo => Key::Redo,
            NamedKey::RfBypass => Key::RfBypass,
            NamedKey::Romaji => Key::Romaji,
            NamedKey::STBInput => Key::STBInput,
            NamedKey::STBPower => Key::STBPower,
            NamedKey::Save => Key::Save,
            NamedKey::ScanChannelsToggle => Key::ScanChannelsToggle,
            NamedKey::ScreenModeNext => Key::ScreenModeNext,
            NamedKey::ScrollLock => Key::ScrollLock,
            NamedKey::Select => Key::Select,
            NamedKey::Settings => Key::Settings,
            NamedKey::Shift => Key::Shift,
            NamedKey::SingleCandidate => Key::SingleCandidate,
            NamedKey::Soft1 => Key::Soft1,
            NamedKey::Soft2 => Key::Soft2,
            NamedKey::Soft3 => Key::Soft3,
            NamedKey::Soft4 => Key::Soft4,
            NamedKey::Space => Key::Character(" ".to_string()),
            NamedKey::SpeechCorrectionList => Key::SpeechCorrectionList,
            NamedKey::SpeechInputToggle => Key::SpeechInputToggle,
            NamedKey::SpellCheck => Key::SpellCheck,
            NamedKey::SplitScreenToggle => Key::SplitScreenToggle,
            NamedKey::Standby => Key::Standby,
            NamedKey::Subtitle => Key::Subtitle,
            NamedKey::Super => Key::Super,
            NamedKey::Symbol => Key::Symbol,
            NamedKey::SymbolLock => Key::SymbolLock,
            NamedKey::TV => Key::TV,
            NamedKey::TV3DMode => Key::TV3DMode,
            NamedKey::TVAntennaCable => Key::TVAntennaCable,
            NamedKey::TVAudioDescription => Key::TVAudioDescription,
            NamedKey::TVAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
            NamedKey::TVAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
            NamedKey::TVContentsMenu => Key::TVContentsMenu,
            NamedKey::TVDataService => Key::TVDataService,
            NamedKey::TVInput => Key::TVInput,
            NamedKey::TVInputComponent1 => Key::TVInputComponent1,
            NamedKey::TVInputComponent2 => Key::TVInputComponent2,
            NamedKey::TVInputComposite1 => Key::TVInputComposite1,
            NamedKey::TVInputComposite2 => Key::TVInputComposite2,
            NamedKey::TVInputHDMI1 => Key::TVInputHDMI1,
            NamedKey::TVInputHDMI2 => Key::TVInputHDMI2,
            NamedKey::TVInputHDMI3 => Key::TVInputHDMI3,
            NamedKey::TVInputHDMI4 => Key::TVInputHDMI4,
            NamedKey::TVInputVGA1 => Key::TVInputVGA1,
            NamedKey::TVMediaContext => Key::TVMediaContext,
            NamedKey::TVNetwork => Key::TVNetwork,
            NamedKey::TVNumberEntry => Key::TVNumberEntry,
            NamedKey::TVPower => Key::TVPower,
            NamedKey::TVRadioService => Key::TVRadioService,
            NamedKey::TVSatellite => Key::TVSatellite,
            NamedKey::TVSatelliteBS => Key::TVSatelliteBS,
            NamedKey::TVSatelliteCS => Key::TVSatelliteCS,
            NamedKey::TVSatelliteToggle => Key::TVSatelliteToggle,
            NamedKey::TVTerrestrialAnalog => Key::TVTerrestrialAnalog,
            NamedKey::TVTerrestrialDigital => Key::TVTerrestrialDigital,
            NamedKey::TVTimer => Key::TVTimer,
            NamedKey::Tab => Key::Tab,
            NamedKey::Teletext => Key::Teletext,
            NamedKey::Undo => Key::Undo,
            NamedKey::VideoModeNext => Key::VideoModeNext,
            NamedKey::VoiceDial => Key::VoiceDial,
            NamedKey::WakeUp => Key::WakeUp,
            NamedKey::Wink => Key::Wink,
            NamedKey::Zenkaku => Key::Zenkaku,
            NamedKey::ZenkakuHankaku => Key::ZenkakuHankaku,
            NamedKey::ZoomIn => Key::ZoomIn,
            NamedKey::ZoomOut => Key::ZoomOut,
            NamedKey::ZoomToggle => Key::ZoomToggle,
            _ => Key::Unidentified,
        }
    }
}

impl FromWinitKeyEvent for Location {
    fn from_winit_key_event(key_event: &KeyEvent) -> Self {
        match key_event.location {
            WinitKeyLocation::Left => Location::Left,
            WinitKeyLocation::Numpad => Location::Numpad,
            WinitKeyLocation::Right => Location::Right,
            WinitKeyLocation::Standard => Location::Standard,
        }
    }
}

impl FromWinitKeyEvent for Code {
    fn from_winit_key_event(key_event: &KeyEvent) -> Self {
        let key_code = match key_event.physical_key {
            PhysicalKey::Code(key_code) => key_code,
            PhysicalKey::Unidentified(_os_code) => return Code::Unidentified,
        };

        match key_code {
            KeyCode::Abort => Code::Abort,
            KeyCode::Again => Code::Again,
            KeyCode::AltLeft => Code::AltLeft,
            KeyCode::AltRight => Code::AltRight,
            KeyCode::ArrowDown => Code::ArrowDown,
            KeyCode::ArrowLeft => Code::ArrowLeft,
            KeyCode::ArrowRight => Code::ArrowRight,
            KeyCode::ArrowUp => Code::ArrowUp,
            KeyCode::AudioVolumeDown => Code::AudioVolumeDown,
            KeyCode::AudioVolumeMute => Code::AudioVolumeMute,
            KeyCode::AudioVolumeUp => Code::AudioVolumeUp,
            KeyCode::Backquote => Code::Backquote,
            KeyCode::Backslash => Code::Backslash,
            KeyCode::Backspace => Code::Backspace,
            KeyCode::BracketLeft => Code::BracketLeft,
            KeyCode::BracketRight => Code::BracketRight,
            KeyCode::BrowserBack => Code::BrowserBack,
            KeyCode::BrowserFavorites => Code::BrowserFavorites,
            KeyCode::BrowserForward => Code::BrowserForward,
            KeyCode::BrowserHome => Code::BrowserHome,
            KeyCode::BrowserRefresh => Code::BrowserRefresh,
            KeyCode::BrowserSearch => Code::BrowserSearch,
            KeyCode::BrowserStop => Code::BrowserStop,
            KeyCode::CapsLock => Code::CapsLock,
            KeyCode::Comma => Code::Comma,
            KeyCode::ContextMenu => Code::ContextMenu,
            KeyCode::ControlLeft => Code::ControlLeft,
            KeyCode::ControlRight => Code::ControlRight,
            KeyCode::Convert => Code::Convert,
            KeyCode::Copy => Code::Copy,
            KeyCode::Cut => Code::Cut,
            KeyCode::Delete => Code::Delete,
            KeyCode::Digit0 => Code::Digit0,
            KeyCode::Digit1 => Code::Digit1,
            KeyCode::Digit2 => Code::Digit2,
            KeyCode::Digit3 => Code::Digit3,
            KeyCode::Digit4 => Code::Digit4,
            KeyCode::Digit5 => Code::Digit5,
            KeyCode::Digit6 => Code::Digit6,
            KeyCode::Digit7 => Code::Digit7,
            KeyCode::Digit8 => Code::Digit8,
            KeyCode::Digit9 => Code::Digit9,
            KeyCode::Eject => Code::Eject,
            KeyCode::End => Code::End,
            KeyCode::Enter => Code::Enter,
            KeyCode::Equal => Code::Equal,
            KeyCode::Escape => Code::Escape,
            KeyCode::F1 => Code::F1,
            KeyCode::F10 => Code::F10,
            KeyCode::F11 => Code::F11,
            KeyCode::F12 => Code::F12,
            KeyCode::F13 => Code::F13,
            KeyCode::F14 => Code::F14,
            KeyCode::F15 => Code::F15,
            KeyCode::F16 => Code::F16,
            KeyCode::F17 => Code::F17,
            KeyCode::F18 => Code::F18,
            KeyCode::F19 => Code::F19,
            KeyCode::F2 => Code::F2,
            KeyCode::F20 => Code::F20,
            KeyCode::F21 => Code::F21,
            KeyCode::F22 => Code::F22,
            KeyCode::F23 => Code::F23,
            KeyCode::F24 => Code::F24,
            KeyCode::F25 => Code::F25,
            KeyCode::F26 => Code::F26,
            KeyCode::F27 => Code::F27,
            KeyCode::F28 => Code::F28,
            KeyCode::F29 => Code::F29,
            KeyCode::F3 => Code::F3,
            KeyCode::F30 => Code::F30,
            KeyCode::F31 => Code::F31,
            KeyCode::F32 => Code::F32,
            KeyCode::F33 => Code::F33,
            KeyCode::F34 => Code::F34,
            KeyCode::F35 => Code::F35,
            KeyCode::F4 => Code::F4,
            KeyCode::F5 => Code::F5,
            KeyCode::F6 => Code::F6,
            KeyCode::F7 => Code::F7,
            KeyCode::F8 => Code::F8,
            KeyCode::F9 => Code::F9,
            KeyCode::Find => Code::Find,
            KeyCode::Fn => Code::Fn,
            KeyCode::FnLock => Code::FnLock,
            KeyCode::Help => Code::Help,
            KeyCode::Hiragana => Code::Hiragana,
            KeyCode::Home => Code::Home,
            KeyCode::Hyper => Code::Hyper,
            KeyCode::Insert => Code::Insert,
            KeyCode::IntlBackslash => Code::IntlBackslash,
            KeyCode::IntlRo => Code::IntlRo,
            KeyCode::IntlYen => Code::IntlYen,
            KeyCode::KanaMode => Code::KanaMode,
            KeyCode::Katakana => Code::Katakana,
            KeyCode::KeyA => Code::KeyA,
            KeyCode::KeyB => Code::KeyB,
            KeyCode::KeyC => Code::KeyC,
            KeyCode::KeyD => Code::KeyD,
            KeyCode::KeyE => Code::KeyE,
            KeyCode::KeyF => Code::KeyF,
            KeyCode::KeyG => Code::KeyG,
            KeyCode::KeyH => Code::KeyH,
            KeyCode::KeyI => Code::KeyI,
            KeyCode::KeyJ => Code::KeyJ,
            KeyCode::KeyK => Code::KeyK,
            KeyCode::KeyL => Code::KeyL,
            KeyCode::KeyM => Code::KeyM,
            KeyCode::KeyN => Code::KeyN,
            KeyCode::KeyO => Code::KeyO,
            KeyCode::KeyP => Code::KeyP,
            KeyCode::KeyQ => Code::KeyQ,
            KeyCode::KeyR => Code::KeyR,
            KeyCode::KeyS => Code::KeyS,
            KeyCode::KeyT => Code::KeyT,
            KeyCode::KeyU => Code::KeyU,
            KeyCode::KeyV => Code::KeyV,
            KeyCode::KeyW => Code::KeyW,
            KeyCode::KeyX => Code::KeyX,
            KeyCode::KeyY => Code::KeyY,
            KeyCode::KeyZ => Code::KeyZ,
            KeyCode::Lang1 => Code::Lang1,
            KeyCode::Lang2 => Code::Lang2,
            KeyCode::Lang3 => Code::Lang3,
            KeyCode::Lang4 => Code::Lang4,
            KeyCode::Lang5 => Code::Lang5,
            KeyCode::LaunchApp1 => Code::LaunchApp1,
            KeyCode::LaunchApp2 => Code::LaunchApp2,
            KeyCode::LaunchMail => Code::LaunchMail,
            KeyCode::MediaPlayPause => Code::MediaPlayPause,
            KeyCode::MediaSelect => Code::MediaSelect,
            KeyCode::MediaStop => Code::MediaStop,
            KeyCode::MediaTrackNext => Code::MediaTrackNext,
            KeyCode::MediaTrackPrevious => Code::MediaTrackPrevious,
            KeyCode::Meta => Code::Super,
            KeyCode::Minus => Code::Minus,
            KeyCode::NonConvert => Code::NonConvert,
            KeyCode::NumLock => Code::NumLock,
            KeyCode::Numpad0 => Code::Numpad0,
            KeyCode::Numpad1 => Code::Numpad1,
            KeyCode::Numpad2 => Code::Numpad2,
            KeyCode::Numpad3 => Code::Numpad3,
            KeyCode::Numpad4 => Code::Numpad4,
            KeyCode::Numpad5 => Code::Numpad5,
            KeyCode::Numpad6 => Code::Numpad6,
            KeyCode::Numpad7 => Code::Numpad7,
            KeyCode::Numpad8 => Code::Numpad8,
            KeyCode::Numpad9 => Code::Numpad9,
            KeyCode::NumpadAdd => Code::NumpadAdd,
            KeyCode::NumpadBackspace => Code::NumpadBackspace,
            KeyCode::NumpadClear => Code::NumpadClear,
            KeyCode::NumpadClearEntry => Code::NumpadClearEntry,
            KeyCode::NumpadComma => Code::NumpadComma,
            KeyCode::NumpadDecimal => Code::NumpadDecimal,
            KeyCode::NumpadDivide => Code::NumpadDivide,
            KeyCode::NumpadEnter => Code::NumpadEnter,
            KeyCode::NumpadEqual => Code::NumpadEqual,
            KeyCode::NumpadHash => Code::NumpadHash,
            KeyCode::NumpadMemoryAdd => Code::NumpadMemoryAdd,
            KeyCode::NumpadMemoryClear => Code::NumpadMemoryClear,
            KeyCode::NumpadMemoryRecall => Code::NumpadMemoryRecall,
            KeyCode::NumpadMemoryStore => Code::NumpadMemoryStore,
            KeyCode::NumpadMemorySubtract => Code::NumpadMemorySubtract,
            KeyCode::NumpadMultiply => Code::NumpadMultiply,
            KeyCode::NumpadParenLeft => Code::NumpadParenLeft,
            KeyCode::NumpadParenRight => Code::NumpadParenRight,
            KeyCode::NumpadStar => Code::NumpadStar,
            KeyCode::NumpadSubtract => Code::NumpadSubtract,
            KeyCode::Open => Code::Open,
            KeyCode::PageDown => Code::PageDown,
            KeyCode::PageUp => Code::PageUp,
            KeyCode::Paste => Code::Paste,
            KeyCode::Pause => Code::Pause,
            KeyCode::Period => Code::Period,
            KeyCode::Power => Code::Power,
            KeyCode::PrintScreen => Code::PrintScreen,
            KeyCode::Props => Code::Props,
            KeyCode::Quote => Code::Quote,
            KeyCode::Resume => Code::Resume,
            KeyCode::ScrollLock => Code::ScrollLock,
            KeyCode::Select => Code::Select,
            KeyCode::Semicolon => Code::Semicolon,
            KeyCode::ShiftLeft => Code::ShiftLeft,
            KeyCode::ShiftRight => Code::ShiftRight,
            KeyCode::Slash => Code::Slash,
            KeyCode::Sleep => Code::Sleep,
            KeyCode::Space => Code::Space,
            KeyCode::SuperLeft => Code::MetaLeft,
            KeyCode::SuperRight => Code::MetaRight,
            KeyCode::Suspend => Code::Suspend,
            KeyCode::Tab => Code::Tab,
            KeyCode::Turbo => Code::Turbo,
            KeyCode::Undo => Code::Undo,
            KeyCode::WakeUp => Code::WakeUp,
            _ => Code::Unidentified,
        }
    }
}

impl FromWinitKeyEvent for KeyState {
    fn from_winit_key_event(key_event: &KeyEvent) -> Self {
        match key_event.state {
            ElementState::Pressed => KeyState::Down,
            ElementState::Released => KeyState::Up,
        }
    }
}

fn keyboard_modifiers_from_winit_modifiers(mods: ModifiersState) -> Modifiers {
    let mut modifiers = Modifiers::empty();
    modifiers.set(Modifiers::CONTROL, mods.control_key());
    modifiers.set(Modifiers::SHIFT, mods.shift_key());
    modifiers.set(Modifiers::ALT, mods.alt_key());
    modifiers.set(Modifiers::META, mods.super_key());
    modifiers
}

pub fn keyboard_event_from_winit(key_event: &KeyEvent, state: ModifiersState) -> KeyboardEvent {
    KeyboardEvent {
        state: KeyState::from_winit_key_event(key_event),
        key: Key::from_winit_key_event(key_event),
        code: Code::from_winit_key_event(key_event),
        location: Location::from_winit_key_event(key_event),
        modifiers: keyboard_modifiers_from_winit_modifiers(state),
        repeat: false,
        is_composing: false,
    }
}
